
import Foundation
import UIKit
extension JX_TypeWrapper where T == String {
    
    // trim the white space and new lines
    public var trim: String {
        return SELF.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    public var isMobile: Bool {
        if SELF.count == 0 {
            return false
        }
        
        let regax = "1[0-9]{10}"
        let test = NSPredicate(format: "SELF MATCHES %@", argumentArray: [regax])
        return test.evaluate(with: SELF)
    }
    
    /// whether a string is email format
    public var isEmailFormat: Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
        
        let emailCheck = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailCheck.evaluate(with: SELF)
    }
    
    // - Returns: url encoded string
    public func urlEncoded() -> String? {
        var charset = CharacterSet.urlHostAllowed
        charset.remove(charactersIn: ";/?:@&=()$, ")
        return SELF.addingPercentEncoding(withAllowedCharacters: charset)
    }
    
    public func attributedString(withLineSpacing lineSpacing: CGFloat) -> NSAttributedString {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        let attr = [NSAttributedStringKey.paragraphStyle: paragraphStyle]
        return NSAttributedString(string: SELF, attributes: attr)
    }

    
}

extension String {
    
    public func initializeClass()->AnyClass?{
        
        let cls : AnyClass? = NSClassFromString(self)
        
        return cls ?? nil
    }
    
}

extension String{
    
    static func refuseAllSpecialWorldTextField(_ textField: UITextField?, textLength length: Int) -> String? {
        let resultStr = String.settingTextField(textField, textLength: length, myBlock: { str in
            return str?.isHaveSpecialWorld() ?? false
        })
        return resultStr
    }
    static func refuseOnlyEmojiTextField(_ textField: UITextField?, textLength length: Int) -> String? {
        let resultStr = String.settingTextField(textField, textLength: length, myBlock: { str in
            return str?.containEmoji() ?? false
        })
        return resultStr
    }
    static func containSpecialWorld(_ specialWorld: String?, textField: UITextField?, textLength length: Int) -> String? {
        let resultStr = String.settingTextField(textField, textLength: length, myBlock: { str in
            return str?.customizeSpecialWorld(specialWorld) ?? false
        })
        return resultStr
    }
    
    static func settingTextField(_ textField: UITextField?, textLength length: Int, myBlock: @escaping (_ str: String?) -> Bool) -> String? {
        var toBeString = textField?.text
        //获取高亮部分
        let selectedRange: UITextRange? = textField?.markedTextRange
        var position: UITextPosition? = nil
        if let start = selectedRange?.start {
            position = textField?.position(from: start, offset: 0)
        }
        // 没有高亮选择的字
        if position == nil {
            if (toBeString?.count ?? 0) > 0 {
                //有特殊字符
                while myBlock(toBeString) {
                    if (toBeString?.count ?? 0) <= 1 {
                        toBeString = ""
                        //因为@""也当做特殊字符了，这里不break就会一直在这里递归 出不去了
                        break
                    } else {
                        var range: NSRange
                        if toBeString?.containEmoji() != nil {
                            //如果有表情 则需要删除两个字节长度 因为表情都是长度为2
                            range = NSRange(location: 0, length: (toBeString?.count ?? 0) - 2)
                        } else {
                            range = NSRange(location: 0, length: (toBeString?.count ?? 0) - 1)
                        }
                        toBeString = (toBeString as NSString?)?.substring(with: range)
                    }
                }
                if length > 0 {
                    //长度超过length
                    if (toBeString?.count ?? 0) > length {
                        let rangeIndex: NSRange? = (toBeString as NSString?)?.rangeOfComposedCharacterSequence(at: length)
                        if Int(rangeIndex?.length ?? 0) == 1 {
                            toBeString = (toBeString as? NSString)?.substring(to: length)
                        } else {
                            let rangeRange = (toBeString as NSString?)?.rangeOfComposedCharacterSequences(for: NSRange(location: 0, length: length))
                            if let rangeRange = rangeRange {
                                toBeString = (toBeString as NSString?)?.substring(with: rangeRange)
                            }
                        }
                    }
                }
            }
            textField?.text = toBeString
        }
        return toBeString
    }
    
    func customizeSpecialWorld(_ specialWorld: String?) -> Bool {
        let pattern = "^[\u{4E00}-\u{9FA5}A-Za-z0-9\(specialWorld ?? "")]+$"
        let pred = NSPredicate(format: "SELF MATCHES %@", pattern)
        let isMatch: Bool = pred.evaluate(with: self)
        return !isMatch
    }
    
    func isHaveSpecialWorld() -> Bool {
        let pattern = "^[\u{4E00}-\u{9FA5}A-Za-z0-9]+$"
        let pred = NSPredicate(format: "SELF MATCHES %@", pattern)
        let isMatch: Bool = pred.evaluate(with: self)
        return !isMatch
    }
    
    func containEmoji()->Bool{
        
//        var testS = "testS"
        
        let len: Int = self.lengthOfBytes(using: .utf8)
        
        if len < 3 {
            // 大于2个字符需要验证Emoji(有些Emoji仅三个字符)
            return false
        }
        
        let data: Data = self.data(using: .utf8)!
        
        //var bts = data?.bytes as? Byte
        var bts = [UInt8](data)
        
        var bt: UInt8?
        var v: Int16 = 0
        for var i in 0..<len {
            bt = bts[i]
            if (Int(bt ?? 0) | 0x7f) == 0x7f {
                // 0xxxxxxxASIIC编码
                continue
            }
            if (Int(bt ?? 0) | 0x1f) == 0xdf {
                // 110xxxxx两个字节的字符
                i += 1
                continue
            }
            if ((bt ?? 0) | 0x0f) == 0xef {
                // 1110xxxx三个字节的字符(重点过滤项目)
                // 计算Unicode下标
                v = Int16((bt ?? 0) & 0x0f)
                v = Int16((v) << 6)
                v |= Int16((bts[i + 1] ) & 0x3f)
                v = Int16(Int(v) << 6)
                v |= Int16((bts[i + 2] ) & 0x3f)
                // NSLog(@"%02X%02X", (Byte)(v >> 8), (Byte)(v & 0xFF));
                if emojiInSoftBankUnicode(code: v) || emojiInUnicode(code: v) {
                    return true
                }
                i += 2
                continue
            }
            if ((bt ?? 0) | 0x3f) == 0xbf {
                // 10xxxxxx10开头,为数据字节,直接过滤
                continue
            }
            return true // 不是以上情况的字符全部超过三个字节,做Emoji处理
        }
        return false
        
        
    }
    
    
    func emojiInSoftBankUnicode(code:Int16)->Bool{
        return ((code >> 8) >= 0xE0 && (code >> 8) <= 0xE5 && Int8(code & 0xFF) < 0x60);
    }
    
    func emojiInUnicode(code:Int16)->Bool{
        if (code == 0x0023
            || code == 0x002A
            || (code >= 0x0030 && code <= 0x0039)
            || code == 0x00A9
            || code == 0x00AE
            || code == 0x203C
            || code == 0x2049
            || code == 0x2122
            || code == 0x2139
            || (code >= 0x2194 && code <= 0x2199)
            || code == 0x21A9 || code == 0x21AA
            || code == 0x231A || code == 0x231B
            || code == 0x2328
            || code == 0x23CF
            || (code >= 0x23E9 && code <= 0x23F3)
            || (code >= 0x23F8 && code <= 0x23FA)
            || code == 0x24C2
            || code == 0x25AA || code == 0x25AB
            || code == 0x25B6
            || code == 0x25C0
            || (code >= 0x25FB && code <= 0x25FE)
            || (code >= 0x2600 && code <= 0x2604)
            || code == 0x260E
            || code == 0x2611
            || code == 0x2614 || code == 0x2615
            || code == 0x2618
            || code == 0x261D
            || code == 0x2620
            || code == 0x2622 || code == 0x2623
            || code == 0x2626
            || code == 0x262A
            || code == 0x262E || code == 0x262F
            || (code >= 0x2638 && code <= 0x263A)
            || (code >= 0x2648 && code <= 0x2653)
            || code == 0x2660
            || code == 0x2663
            || code == 0x2665 || code == 0x2666
            || code == 0x2668
            || code == 0x267B
            || code == 0x267F
            || (code >= 0x2692 && code <= 0x2694)
            || code == 0x2696 || code == 0x2697
            || code == 0x2699
            || code == 0x269B || code == 0x269C
            || code == 0x26A0 || code == 0x26A1
            || code == 0x26AA || code == 0x26AB
            || code == 0x26B0 || code == 0x26B1
            || code == 0x26BD || code == 0x26BE
            || code == 0x26C4 || code == 0x26C5
            || code == 0x26C8
            || code == 0x26CE
            || code == 0x26CF
            || code == 0x26D1
            || code == 0x26D3 || code == 0x26D4
            || code == 0x26E9 || code == 0x26EA
            || (code >= 0x26F0 && code <= 0x26F5)
            || (code >= 0x26F7 && code <= 0x26FA)
            || code == 0x26FD
            || code == 0x2702
            || code == 0x2705
            || (code >= 0x2708 && code <= 0x270D)
            || code == 0x270F
            || code == 0x2712
            || code == 0x2714
            || code == 0x2716
            || code == 0x271D
            || code == 0x2721
            || code == 0x2728
            || code == 0x2733 || code == 0x2734
            || code == 0x2744
            || code == 0x2747
            || code == 0x274C
            || code == 0x274E
            || (code >= 0x2753 && code <= 0x2755)
            || code == 0x2757
            || code == 0x2763 || code == 0x2764
            || (code >= 0x2795 && code <= 0x2797)
            || code == 0x27A1
            || code == 0x27B0
            || code == 0x27BF
            || code == 0x2934 || code == 0x2935
            || (code >= 0x2B05 && code <= 0x2B07)
            || code == 0x2B1B || code == 0x2B1C
            || code == 0x2B50
            || code == 0x2B55
            || code == 0x3030
            || code == 0x303D
            || code == 0x3297
            || code == 0x3299
            // 第二段
            || code == 0x23F0) {
            return true;
        }
        return false;
    }
    
    
}
